﻿using SQLiteSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using YunLuPos.Entity;
using YunLuPos.Entity.Constant;

namespace YunLuPos.DB.Service
{
    public class GroupPromotionService
    {
        private log4net.ILog logger = log4net.LogManager.GetLogger(typeof(GroupPromotionService));
        private SaleOrderGoodsService saleOrderGoodsService = new SaleOrderGoodsService();
        private GoodsService goodsService = new GoodsService();
        /**
         * 根据条码或商品编码获取商品
         * */
        public List<GroupPromotion> getGroupPromotion(String barCode)
        {
            DBLocker.setLocker();
            try
            {
                using (SqlSugarClient db = SugarDao.GetInstance())
                {
                    DateTime dt = DateTime.Now;
                    String currentDate = dt.ToString("yyyyMMdd");
                    String currentTime = dt.ToString("HHmm");
                    List<GroupPromotion> proms = db.SqlQuery<GroupPromotion>(@"
                                                    Select * from GroupPromotion where promCode =
                                                        (select promCode  from GroupPromotion 
                                                        where iStatus = '1' 
                                                        and barCode = @barCode 
                                                        and startDate <= @cD and endDate >= @cD 
                                                        and 
                                                        ((startTime <= @cT and endTime >= @cT)
                                                            or 
                                                         (startTime ='0000' and endTime = '0000')
                                                        )
                                                        order by ver desc limit 1)",
                                                     new { barCode = barCode, cD = currentDate, cT = currentTime }
                                                    )
                                                   .ToList();

                    if (proms != null)
                    {
                        return proms;
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex);
            }
            finally
            {
                DBLocker.release();
            }
            return null;
        }


        /**
         * 根据条码或商品编码获取商品
         * */
        public List<GroupPromotionCheck> checkGroupProm(SaleOrder order)
        {
            DBLocker.setLocker();
            try
            {
                
                using (SqlSugarClient db = SugarDao.GetInstance())
                {   
                    DateTime dt = DateTime.Now;
                    String currentDate = dt.ToString("yyyyMMdd");
                    String currentTime = dt.ToString("HHmm");

                    List<String[]> proms = db.SqlQuery<String[]>(@"SELECT
			                                                    GroupPromotion.promCode,
			                                                    GroupPromotion.groupNum,
                                                                GroupPromotion.barCode,
			                                                    GroupPromotion.groupCount,
			                                                    SUM(ifnull(SaleOrderGoods.goodsCount,0)) as goodsCount,
			                                                    GroupPromotion.groupCount - SUM(ifnull(SaleOrderGoods.goodsCount,0)) AS deff,
                                                                GroupPromotion.groupPrice,
			                                                    round(GroupPromotion.groupPrice / GroupPromotion.groupCount,2) as groupAvgPrice

                                                    FROM GroupPromotion 
                                                    LEFT JOIN 
	                                                    (SELECT barCode,
				                                                    sum(ifnull(goodsCount,0)) AS goodsCount 
				                                                    FROM SaleOrderGoods 
				                                                    WHERE orderCode = @orderCode
				                                                    AND priceSource = 'NORM' 
				                                                    GROUP BY barCode) 
	                                                    SaleOrderGoods
                                                    ON GroupPromotion.barCode = SaleOrderGoods.barCode

                                                    WHERE GroupPromotion.iStatus = '1' 
                                                    AND  startDate <=  @cD and endDate >=  @cD 
                                                    AND	(
	                                                    (startTime <=  @cT and endTime >=  @cT)
			                                                    or 
	                                                    (startTime ='0000' and endTime = '0000')
                                                    )
                                                    GROUP BY GroupPromotion.groupCount,GroupPromotion.promCode,GroupPromotion.groupNum,GroupPromotion.barCode",
                                                     new { orderCode = order.orderCode, cD = currentDate, cT = currentTime }
                                                    ).ToList();

                    if (proms != null && proms.Count > 0)
                    {
                        List<GroupPromotionCheck> checks = new List<GroupPromotionCheck>();
                        foreach(String[] check in proms)
                        {
                            GroupPromotionCheck c = new GroupPromotionCheck();
                            c.promCode = check[0];
                            c.groupNum = check[1];
                            c.barCode = check[2];
                            c.groupCount = Double.Parse(check[3]);
                            c.goodsCount = Double.Parse(check[4]);
                            c.deff = Double.Parse(check[5]);
                            c.groupPrice = Double.Parse(check[6]);
                            c.groupAvgPrice = Double.Parse(check[7]);
                            if (c.deff > 0)
                            {
                                return null;
                            }
                            checks.Add(c);
                        }
                        return checks;
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex);
            }
            finally
            {
                DBLocker.release();
            }
            return null;
        }

        /**
         * 订单组合促销计算
         * 同一个组合促销方案中条码不可重复
         * 同一组中的组价格与组数量必须一致
         * 1.检查单据是否有满足条件的组合促销方案，并返回方案组合信息GroupPromotionCheck列表
         * 2.根据数量排序列出所有正常价格商品
         * 3.循环方案信息如商品列表中的数量小于等于方案数量修改商品列表状态
         *   如大于方案数量拆分列表并修改状态
         */
        public Boolean doGroupProm(SaleOrder order)
        {
            List<GroupPromotionCheck> gpc = checkGroupProm(order);
            if (gpc == null || gpc.Count <= 0)
            {
                return false;
            }
            Console.WriteLine("chekced");
            DBLocker.setLocker();
            using (SqlSugarClient db = SugarDao.GetInstance())
            {
                try
                {
                    List<SaleOrderGoods> goods = db.Queryable<SaleOrderGoods>()
                            .Where(it => it.orderCode == order.orderCode && it.priceSource == GoodsPriceSource.NORM.ToString())
                            .OrderBy(it => it.goodsCount,OrderByType.Asc)
                            .ToList();
                    db.BeginTran();
                    foreach(GroupPromotionCheck c in gpc)
                    {
                        Double currentCount = c.groupCount;
                        Double currentPrice = c.groupPrice;
                        foreach (SaleOrderGoods g in goods)
                        {
                            if (c.barCode.Equals(g.barCode) && currentCount > 0)
                            {
                                
                                if(g.goodsCount <= currentCount)
                                {
                                    //明细数量小于等于组合数量
                                    currentCount = currentCount - g.goodsCount;
                                    currentPrice = Math.Round(currentPrice - g.goodsCount * c.groupAvgPrice,2);
                                    Boolean b = db.Update<SaleOrderGoods>(
                                        new {
                                             disPrice = c.groupAvgPrice,
                                             realAmount =  g.goodsCount * g.price,
                                             payAmount = g.goodsCount * c.groupAvgPrice,
                                             disAmount = (g.goodsCount * g.price) - (g.goodsCount * c.groupAvgPrice),
                                             priceSource = GoodsPriceSource.GROUP_PROM.ToString(),
                                             promCode = c.promCode },
                                        it => it.id == g.id);
                                    if (!b)
                                    {
                                        db.RollbackTran();
                                        return false;
                                    }
                                }else
                                {
                                    //明细数量大于组合数量 分隔明细并设置
                                    SaleOrderGoods orderGoods = new SaleOrderGoods();
                                    orderGoods.orderId = g.orderId;
                                    orderGoods.orderCode = g.orderCode;
                                    orderGoods.cliqueCode = g.cliqueCode;
                                    orderGoods.branchCode = g.branchCode;
                                    orderGoods.goodsCode = g.goodsCode;
                                    orderGoods.goodsName = g.goodsName;
                                    orderGoods.specs = g.specs;
                                    orderGoods.unit = g.unit;
                                    orderGoods.barCode = g.barCode;
                                    orderGoods.packCount = g.packCount;
                                    orderGoods.goodsCount = currentCount;
                                    orderGoods.price = g.price;
                                    orderGoods.disPrice = c.groupAvgPrice;
                                    orderGoods.disCount = 100;
                                    orderGoods.promCode = c.promCode;
                                    orderGoods.realAmount = orderGoods.goodsCount * orderGoods.price;
                                    orderGoods.payAmount = currentPrice;// orderGoods.goodsCount * orderGoods.disPrice;
                                    orderGoods.disAmount = (orderGoods.realAmount - orderGoods.payAmount);
                                    orderGoods.priceSource = GoodsPriceSource.GROUP_PROM.ToString();

                                    Int64 result = (Int64)db.Insert<SaleOrderGoods>(orderGoods);
                                    if (result <= 0)
                                    {
                                        db.RollbackTran();
                                        return false;
                                    }
                                    Boolean b = db.Update<SaleOrderGoods>(new {
                                        goodsCount = g.goodsCount - currentCount,
                                        realAmount = (g.goodsCount - currentCount) * g.price,
                                        payAmount = (g.goodsCount - currentCount) * g.disPrice,
                                    }, it => it.id == g.id);
                                    if (!b)
                                    {
                                        db.RollbackTran();
                                        return false;
                                    }
                                    currentCount = 0;
                                    //不需要后续处理
                                    currentPrice = -1;
                                    Console.WriteLine("sprlit" + "   " + currentPrice);
                                }
                                
                                //处理差值组合促销存在除不尽情况
                                if (currentCount == 0 && currentPrice > 0)
                                {
                                    Console.WriteLine("处理差值" + g.barCode);
                                    Double lastPrice = Math.Round( c.groupAvgPrice + currentPrice ,2);
                                    if (g.goodsCount == 1)
                                    {
                                        //商品列表数量等于1修改价格与小计金额
                                        Boolean b = db.Update<SaleOrderGoods>(
                                              new
                                              {
                                                  disPrice = lastPrice,
                                                  payAmount = lastPrice,
                                                  disAmount = (g.goodsCount * g.price) -  lastPrice,
                                              },
                                              it => it.id == g.id);
                                        if (!b)
                                        {
                                            db.RollbackTran();
                                            return false;
                                        }
                                    }
                                    else
                                    {
                                        //商品列表数量不等于1修改小计金额
                                       Boolean b = db.Update<SaleOrderGoods>(
                                             new
                                             {
                                                 payAmount = Math.Round( (g.goodsCount * c.groupAvgPrice) + currentPrice  , 2),
                                                 disAmount = Math.Round((g.goodsCount * g.price) - ((g.goodsCount * c.groupAvgPrice) + currentPrice) ,2),
                                             },
                                             it => it.id == g.id);
                                        if (!b)
                                        {
                                            db.RollbackTran();
                                            return false;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    //更新主单据信息
                    Int32 r = db.ExecuteCommand(@"UPDATE SaleOrder SET 
		            goodsCount = (select sum(goodsCount) from SaleOrderGoods where orderId = @o GROUP BY orderId),
		            realAmount = (select sum(realAmount) from SaleOrderGoods where orderId = @o GROUP BY orderId),
		            payAmount = (select sum(payAmount) from SaleOrderGoods where orderId = @o GROUP BY orderId),
		            disAmount = (select sum(disAmount) from SaleOrderGoods where orderId = @o GROUP BY orderId)
                    WHERE orderId = @o", new
                    {
                        o = order.orderId,
                    });

                    if (r > 0)
                    {
                        db.CommitTran();
                        return true;
                    }
                    else
                    {
                        db.RollbackTran();
                    }
                }
                catch (Exception ex)
                {
                    db.RollbackTran();
                    logger.Error(ex);
                }
                finally
                {
                    DBLocker.release();
                }
            }
            return true;
        }



        public String maxVersion()
        {
            DBLocker.setLocker();
            try
            {
                using (SqlSugarClient db = SugarDao.GetInstance())
                {
                    Object obj = db.Queryable<GroupPromotion>().Max(it => it.ver);
                    if (obj == null || "".Equals(obj.ToString()))
                    {
                        return "0";
                    }
                    else
                    {
                        return obj.ToString();
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex);
            }
            finally
            {
                DBLocker.release();
            }
            return "0";
        }

        /**
       * 批量新增或更新商品
       * */
        public Int64 insertOrUpdate(List<GroupPromotion> proms)
        {
            if (proms == null || proms.Count <= 0)
            {
                return 0;
            }
            DBLocker.setLocker();
            SqlSugarClient db = null;
            try
            {
                using (db = SugarDao.GetInstance())
                {
                    db.BeginTran();
                    foreach (GroupPromotion p in proms)
                    {
                        GroupPromotion dbPromotion = db.Queryable<GroupPromotion>()
                            .Where(it => it.promCode == p.promCode && it.barCode == p.barCode && it.goodsCode == p.goodsCode)
                            .SingleOrDefault();
                        if (dbPromotion != null)
                        {
                            db.Delete<GroupPromotion>(it => it.promCode == p.promCode && it.barCode == p.barCode && it.goodsCode == p.goodsCode);
                        }
                        db.Insert<GroupPromotion>(p);
                    }
                    db.CommitTran();
                }
            }
            catch (Exception ex)
            {
                db.RollbackTran();
                logger.Error(ex);
            }
            finally
            {
                DBLocker.release();
            }
            return proms.Count;
        }
    }

    




    public class GroupPromotionCheck
    {
        public string promCode { get; set; }

        public string groupNum { get; set; }

        public string barCode { get; set; }

        public Double groupCount { get; set; }

        public Double goodsCount { get; set; }

        public Double deff { get; set; }

        public Double groupPrice { get; set; }

        public Double groupAvgPrice { get; set; }
    }

}
